Linux: O graceful shutdown
OpenCPN and Linux powerup/down management updated for Ubuntu 20.04 and OpenCPN 5.6.0.
Problem
No clean exit line when when Linux is closed with O still running.
The computer is shutdown without closing OpenCPN first, with unsaved tracks, routes or way-points.
OpenCPN is not responding correctly to the signal that Linux sends to OpenCPN on close down.
If OpenCPN is first closed down and then Linux is closed down, all is OK on restart.
I've been struggling to find a solution to the problem where OpenCPN shuts down 'violently' instead of gratefulas.
In Linux this is not an OpenCPN problem but is related to systemd so I looked for a correct start/stop procedure as published here.
Starting and stopping OpenCPN on a dedicated system with Ubuntu 20.04 using Xfce and lightdm-gtk-greeter.
The machine used is a 'Car-PC' with an M2-ATX power supply but should be applicable om most systems where a 'Power button' (or switch), is used for start and stop.
Prerequisites:
Systemd is, since Ubuntu 15.04, the default method starting and stopping system and applications. Systemd, per default and if no special actions are taken, simply assumes that a running application is closed at the instant a 'SIGTERM' is sent to the application causing programs like OpenCPN being closed not given time to save configuration files or log files.
First:
Disable the BIOS setting for 'Secure Boot', the use of both systemd and acpi combined seems to confuse BIOS, at least on my machine.
Use 'sudo' and make scripts executable when appropriate.
The user need to have enhanced privileges and should not need to supply root password, see info on 'visudo' for how to do that.
Policykit must be updated to allow a normal user to control 'handle-power-key'. Also well explained on the web and briefly explained below.
Ensure that 'env $PATH' lists all locations where the commands used in the scripts are located, test using e.g. 'which sleep'.
Replace the text '<user>' in this description with your login name.
Disable screen locking and screen savers.
OpenCPN shall be run by a dedicated user (not root!) and should, by systemd, be run as that user. This option is badly supported due to the lack of support for graphical shells using targets and services. The method used here will, as there is only one (automatically logged in) user on the system, serve the same purpose. OpenCPN is also run in the background to overcome some of there limitationns.
Enable automatic login:
[SeatDefaults]
autologin-user=<user>
Modify systemd settings:
sudo loginctl enable-linger <user>
Modifying Policykit
Policykit confrols, among other things, how systemd is controlled as not all users have access to all functions. This is the case for power key functions. As this here is used by a normal user need policykit be updated.
Use 'sudo' and update the script '/usr/share/polkit-1/actions/org.freedecktop.login1.policy' looking for the section where 'action id' contains 'handle-power-key'.
Go to the line '<allow_any>no</allow_any>' and update to '<allow_any>yes</allow_any>'.
Start script for OpenCPN:
-----------------
#!/bin/bash
systemd-inhibit --what=handle-power-key --mode=block /usr/bin/opencpn &
exit 0
-----------------
Shut down OpenCPN (if it is running) and execute the script using 'sudo /usr/local/bin/ocpnStart'. OpenCPN shall start.
Press/switch the 'Power button', nothing shall happen as it has been disabled.
Use the command 'systemd-inhibit –list', the message shall say that <user> has used the command to start OpenCPN and that 'handle-power-key' is 'block'
Shut down OpenCPN manually.
Enable systemd to start OpenCPN:
-----------------
[Unit]
Description=opencpn
After=display-manager.service lightdm.service graphical.target
Conflicts=exit.target shutdown.target reboot.target halt.target
[Service]
Type=oneshot
User=<user>
Group=<user>
RemainAfterExit=yes
ExecStartPre=logger Starting OpenCPN Service
# Allow time for GUI to start properly
ExecStartPre=sleep 6
Environment=DISPLAY=:0.0
Environment=Xauthority=/home/<user>/.Xauthority
# The systemd-inhibit function need be in a separate script
ExecStartPre=logger Starting OpenCPN startscript
ExecStart=/usr/local/bin/ocpnStart.sh
ExecStop=logger Shutting down OpenCPN
ExecStop=pkill -15 opencpn
ExecStopPost=logger Kill command sent
ExecStopPost=sleep 5
[Install]
WantedBy=graphical.target
-----------------
The service-script is calling the 'ocpnStart' script to start as well as to stop OpenCPN.
Set the script rights using 'sudo chmod 644 /etc/systemd/system/opencpn.service'
Use the command 'sudo systemd-analyze verify opencpn.service' to verify the script is correct. There shall be no response but the prompt back.
Tell systemd to use the script with the commands 'sudo systemctl daemon-reload' and 'sudo systemctl enable opencpn.service'.
Ensure that OpenCPN is shut down, then give the command 'sudo service opencpn start', OpenCPN shall start. Minimize OpenCPN but leave it running.
Use a second terminal and verify status with the command 'sudo systemctl status opencpn', note the 'CGroup'-line listing the script but not the actual OpenCPN commands. Systemd is hence not able to shut down the 'opencpn' processes (there are actually two) directly.
You may also see a number of ALSA messages, these are another story an can be safely ignored.
Shutting down OpenCPN gracefully:
Install acpi with 'sudo apt-get install acpi acpid', then activate and start the daemon using 'sudo systemctl enable acpid.service' followed by 'sudo systemctl start acpid.service'
Use the command 'acpi_listen' and then push the 'Power button' like if switching of the system. the system will remain on and the window will display something like:
button/power PBTN 00000080 00000000
button/power LNXPWRBN:00 00000080 00000001
button/power PBTN 00000080 00000000
button/power LNXPWRBN:00 00000080 00000002
Both on and off is detected, terminate the listen process with Ctrl + C.
Make a backup copy of the script '/etc/acpi/powerbtn.sh' and then open the original script for editing. This is where the 'Secure boot' may get involved and, like on my system, refuse to bypass the BIOS setup unless disabled.
There are two scripts that need be updated '/etc/acpi/events/power' that detect the button action plus '/etc/acpi/power.sh' that does the actual shutdown.
-----------------
# /etc/acpi/events/power
# This is called when the user presses the power button and calls
# /etc/acpi/powerbtn.sh for further processing.
# We need to react on "button power.*" and "button/power.*" because
# of kernel changes.
event=button[ /]power
action=/etc/acpi/power.sh
-----------------
-----------------
#!/bin/bash
# /etc/acpi/powerbtn.sh
# Initiates a shutdown when power button has been pressed
# Shutdown OpenCPN
sudo systemctl stop opencpn.service
# Shutdown the whole system
shutdown -h now
-----------------
Close all terminals when done and maximize the OpenCPN application.
Press the 'Power button' and here comes the magic: OpenCPN shuts down, one second later followed by a complete system shutdown.
Wait at least 15 seconds and then press the 'Power button' again. The system shall boot and Opencpn shall be started.
Minimize OpenCPN and open a terminal. Use the command 'cat /home/<user>/.opencpn/opencpn.log, the last line on the previous session shall say: 'opencpn::MyApp exiting cleanly…'
If it does, then you are all done . . . almost.
A bonus addition: Shutting down thru Xfce:
This little script replaces the execution of another script with the same name, simply because of the path order.
Install 'wnctrl' using 'sudo apt-get install wmctrl', then generate the executable script '/usr/local/bin/xfce4-session-logout '. Add these lines:
-----------------
#!/bin/bash
wmctrl -c opencpn
sleep 1
/usr/bin/xfce4-session-logout -h
exit 0
-----------------
Once done, close the terminal and maximize OpenCPN (it should still be running)
Click on the menu 'Application → Log out', OpenCPN shuts down and is one second later followed by a complete system shutdown.
A final note: Xfce will, when shut down this way, remember the programs used and open them at next boot. Consider this method an alternative shutdown.
That should be all. Enjoy! Hope this explains my view on what is happening and can be of use to you
Best Regards [LennartG] Lennart Gilander
Addendum
MaVi writes:
Well, first I misread what the line
<Code> sudo sed -e '/shutdown/ s/^#*/#/' -i /etc/rc.local
actually does, which explained why I could not find the trigger for the script. It is triggered at boot time.. So I created a simple script from the graceful shutdown page , basically:
#!/bin/bash
# /etc/acpi/powerbtn.sh
# Initiates a shutdown when power button has been
# pressed
LOGFILE=/home/pi/shutdownlog.log
$USER=pi
echo '$(date) OCPN stop request received'>> $LOGFILE
if /usr/bin/pgrep -u $USER opencpn> /dev/null ; then
echo '$(date) OCPN found running. Stopping now'>> $LOGFILE
/usr/bin/pkill -u $USER opencpn
fi
while (pgrep -x opencpn>/dev/null); do
sleep 1
echo '$(date) Waiting for OCPN to stop'>> $LOGFILE
done
echo '$(date) OCPN stopped'>> $LOGFILE
sleep 2
as killOCPN.sh (and of course chmod +x'ed) Next I added the killOPCN command into the /etc/x710pwr.sh script , just before the 'sudo poweroff' and 'sudo reboot' lines.
The one thing I haven't figured out yet is how to use a simple shutdown button press insted of the long press that is now required- I can shorten the rebootpulsemaximum, but then the X710 does not power-off, but that's for the next rainy sunday afternoon…